#include "Noeud.hpp"
#include "Region.hpp"
int Noeud::m_compteur = 0;
Noeud::Noeud(Noeud * pere):m_pere(pere){
    //incrementation de l'identifiant
    this->m_compteur++;
    //initialisation des fils a null
    for(int i = 0; i<3;i++){
            this->m_fils[i]=NULL;
    }
    m_id = m_compteur;
    m_nbFils = 0;
    m_region = NULL;
}
Noeud::Noeud(Noeud * pere, const Image & image): m_image(image),m_pere(pere){
    //Comparaison des deux moyennes
    this->m_compteur++;
    //initialisation des fils a null
    for(int i = 0; i<3;i++){
            this->m_fils[i]=NULL;
    }
    m_nbFils = 0;
    m_id = m_compteur;
    m_region = NULL;
}
void Noeud::destructNoeud(){
    //Apell recursif sur chacun des fils
    for(int i = 0; i<3;i++){
            if(m_fils[i]!=NULL){
                    m_fils[i]->destructNoeud();
                    delete m_fils[i];
            }
    }
}
bool Noeud::isFeuille(){
	return m_nbFils == 0;
}
void Noeud::maj(){
    //Parcours des adjacents du pere
	for(map<int,Noeud *>::iterator i = m_pere->getAdjacents()->begin() ; i!=m_pere->getAdjacents()->end() ; i++){
		Noeud  * n = (Noeud *)(i->second);
		if(m_image.IsAdjacent(n->getImage())){
                    //mis a jour des adjacence
			n->majAdjacent(m_pere, this);
			addAdjacent(n);
		}else{
                    //supression de l'adjacence
			n->eraseAdjacent(m_pere);
		}
	}
}

void Noeud::majAdjacent(Noeud* pere, Noeud* fils){
    //supression de l'adjacence avec le pere
	m_adjacents.erase(pere->getId());
        //rajout de l'adjacance avec le fils
	m_adjacents[fils->getId()]= fils;
}
void Noeud::eraseAdjacent(Noeud * n){
	m_adjacents.erase(n->getId());
}
int Noeud::getId()const{
	return m_id;
}

map<int, Noeud*> * Noeud::getAdjacents(){
	return &m_adjacents;
}
void Noeud::split(){
    //division uniquement si l'image n'est pas homogene et si elle est assez grnade
        if(!m_image.IsSmal() && !m_image.IsHomogene()){
		vector<Image> vec;
		m_image.split(vec);
		m_nbFils =4;
                //creation des quatre fils
		for(int i = 0; i<4; i++){
			m_fils[i] = new Noeud(this, vec[i]);
		}
                //rajout de ses trois freres commme adjacent
		for(int i = 0; i<4; i++){
			for(int j = 0; j<4; j++){
				if(j!=i){
					m_fils[i]->addAdjacent(m_fils[j]);
				}
			}
		}
                //mis a jour des adjacence
		for(int i = 0; i<4; i++){
			m_fils[i]->maj();
                }
                //apell recursif sur les quatre fils
		for(int i = 0; i<4; i++){
			m_fils[i]->split();
		}
	}	
}
Image & Noeud::getImage(){
	return m_image;
}
void Noeud::afficheMaillage(IplImage *img){
	CvScalar scalaire;
	scalaire.val[0] = rand()%255;
	scalaire.val[1] = rand()%255;
	scalaire.val[2] = rand()%255;
	cvRectangle(img, cvPoint( m_image.getX(),m_image.getY()), cvPoint(m_image.getX()+ m_image.getwidth()-1, m_image.getY()+ m_image.getheight()-1), scalaire, 1);
	if(!isFeuille()){
		for(int i = 0; i<4; i++){
			m_fils[i]->afficheMaillage(img);
		}
	}
}

void Noeud::merge(){
    //test si on se situe sur une feuille de l'arbre
	if(isFeuille()){
                if(m_region==0){
                    //creation d'une region si on appartient a aucune
                        m_region = new RegionImage(this, m_image.getMoyenne());
                        RegionImage::add(m_region);
		}
		vector <Noeud*> nonAdj;
                //parcours des adjacents
		for(map<int,Noeud *>::iterator i = m_adjacents.begin() ; i!=m_adjacents.end() ; i++){
			Noeud  * n = (Noeud *)(i->second);
			//si les deux images sont equivalentes celle de n et celle de this
                        //et si elle ne sont pas de la meme region deja
                        if(m_image.isRessemblant(n->getImage())&& n->getRegion() != m_region){
                                if(n->getRegion()==0){
                                        //ajout du noeud a la region si il na aucune region pour linstant
                                        m_region->ajouteNoeud(n, n->getImage().getMoyenne());
                                }else{
                                   //choix de la plus petite region
                                    if(n->getRegion()->getTaille()<=m_region->getTaille()){
                                        //concatenation des regions
                                        int id = n->getRegion()->getId();
                                            m_region->ajoute(*(n->getRegion()));
                                            RegionImage::erase(id);
                                    }else{
                                        //concatenation des regions
                                        int id = m_region->getId();
                                            n->getRegion()->ajoute(*m_region);
                                             RegionImage::erase(id);
                                    }
				}
                            }
                        nonAdj.push_back(n);
		}
                //supression des relations d'adjacence pour eviter des calculs doubles
		for(int l = 0; l<nonAdj.size();l++){
                    Noeud * e = (Noeud *) nonAdj[l];
                      eraseAdjacent(e);
                      e->eraseAdjacent(this);
		}
		
	}else{
            //appel recursif sur les fils
		for(int i = 0; i<4; i++){
			m_fils[i]->merge();
		}
	}
}
void Noeud::addAdjacent(Noeud * adj){
	m_adjacents[adj->getId()] = adj;
}
RegionImage * Noeud::getRegion(){
	return m_region;
}
void Noeud::setRegion(RegionImage * region){
	m_region = region;
}
void Noeud::afficheRegion(IplImage* im,double color){
	CvScalar scalaire;
	scalaire.val[0] = color;
	cvRectangle(im,cvPoint( m_image.getX(),m_image.getY()), cvPoint(m_image.getX()+ m_image.getwidth()-1, m_image.getY()+ m_image.getheight()-1), scalaire, CV_FILLED);
}
void Noeud::fillImage(QImage & im, QRgb value){
    int x = m_image.getX();
    int y = m_image.getY();
    int width =m_image.getwidth();
    int height = m_image.getheight();

    //parcours de tout les points
    for(int i = x; i<x+ width ; i++){
        for(int j = y; j<y+height; j++){
           im.setPixel(i, j,value);
        }
    }
}
